/*-------------------------------------------------------------------------------
* file:     app_updata.h
* brief:    application
* copyright Copyright (C) 2020-2022 @ NanoIC
* Date:     2022-08-15
* Version:  V1.00
* Author:   JMH
*-------------------------------------------------------------------------------*/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __APP_UPDATA_H__
#define __APP_UPDATA_H__

/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "pin.h"
#include "sys_console.h"
#include "app_cfg.h"
#include "app_spi.h"
#include "app_init.h"
#include "app_factory.h"

#define  CHIP_FLASH_BASE_ADDR            0x00000000     /*  芯片Flash基址  */
#define  FLASH_APP_BASE_ADDR             0x00003000     /*  APP运行区  */

#define  WN8012S_APP_VERSION_ADDR        0x100

#define FLASH_FCT_ADDR                   0xE000         /* SN地址1 */
#define FLASH_FCT_ADDR1                  0xF000         /* SN地址2 */

#define  FLASH_OTA_BASE_ADDR             0x011000       /*  升级临时缓冲区  */
#define  FLASH_SECTION_HEADER_ADDR       0x000100           /*  帧头对应偏移位置  */
#define  FLASH_APP_MAX_SIZE              (1024*54)      /*  APP最大长度  */ //test 为了兼容

#define  FLASH_HEADER_LENGTH              0x40          /*  Header长度  */


//-------------------------------------------------------------------------------
// WN8012S Flash 信息
#define  WN8012_FLASH_MAX_SIZE              (1024*64)
#define  WN8012_FLASH_PAGE_SIZE             0x100
#define  WN8012_FLASH_SECTOR_SIZE           0x1000
//-------------------------------------------------------------------------------
// WN8012S Boot地址
#define  WN8012_BOOT_DATA_ADRESS            0x0000
#define  WN8012_OTA_APP_VER_ADDR            0x100
#define  WN8012_OTA_APP_VID_PID_ADDR        0x110
//-------------------------------------------------------------------------------
// WN8012S 应用程序地址
#define  WN8012_APP_HEAD_LENGTH             64
#define  WN8012_APP_DATA_ADRESS             0x3000
#define  WN8012_APP_HEAD_ADRESS            (WN8012_APP_DATA_ADRESS - WN8012_APP_HEAD_LENGTH)
#define  WN8012_APP_DATA_MAX_LENGTH         (52*1024)
//-------------------------------------------------------------------------------
// WN8012S OTA Flash 地址
#define WN8012_OTA_DATA_ADDRESS             0x011000
#define WN8012_OTA_HEAD_ADDRESS             (WN8012_OTA_DATA_ADDRESS - WN8012_APP_HEAD_LENGTH)

// WN8012S TP OTA Flash 地址
#define WN8012_TP_OTA_DATA_ADDRESS             0x020000
#define  WN8012_TP_DATA_MAX_LENGTH         (64*1024)
//-------------------------------------------------------------------------------
// WN8012S 其它信息
#define  APP_VID_PID_NO_CHECK_FLAG            0xffffffff
#define  APP_HEAD_SYSC_WORD_ONE               0x384E572A
#define  APP_HEAD_SYSC_WORD_TWO               0x2A323130
#define  APP_DATA_DEBUG_FLAG_WORD             0x5D30
//-------------------------------------------------------------------------------
#define  APP_UPGRADE_MAX_ONE_PACKET           52

typedef struct __UpgradeHead_Typedef
{
    uint32_t sync_one;
    uint32_t sync_two;
    uint32_t length;
    uint32_t check_sum;
    uint32_t version;
    uint32_t compile_data;
    uint32_t device_type;
    uint32_t extend_type;
    uint32_t device_id;
    uint32_t aux_info;
    uint32_t rev_01;
    uint32_t rev_02;
    uint32_t rev_03;
    uint32_t rev_04;
    uint32_t rev_05;
    uint8_t  rev_06;
    uint8_t  rev_07;
    uint8_t  rev_08;
    uint8_t  add;
}UpgradeHead_Typedef;

// 读取设备的程序版本信息
#define   APP_UPGRADE_READ_OBJECT_VERSION               0x01 
// 下传数据的帧头信息
#define   APP_UPGRADE_SEND_DATA_HEAD_INFO               0x02  
// 下传复位命令
#define   APP_UPGRADE_CTRL_OBJECT_RESET                 0x03 
// 下传数据完成命令
#define   APP_UPGRADE_SEND_DATA_END                     0x04 
// 启动更新Flash升级
#define   APP_UPGRADE_STAR_FLASH_UPDATA                 0x06
// 下传升级数据
#define   APP_UPGRADE_WRITE_OBJECT_DATA                 0x11
#define   APP_UPGRADE_ACK_WRITE_OBJECT_DATA             0x91

typedef enum
{
	KEY_NO_DEVICE = 0,
	KEY_MAIN_CPU = 1,
	KEY_DEV_CPU = 2,
}KEY_UPGRADE_DEVICE_E;

typedef struct __UpgradeInfo_Typedef
{
    //----------------------------------------------------------
    // 升级文件信息
    uint32_t length;                // 升级文件长度
    uint32_t start_addr;            // 升级文件启始地址，用于区分MCU、外设
                                    // MCU: 0x58000
    uint32_t checksum;              // 升级文件累加和
    uint32_t version;               // 升级文件版本号
    uint32_t pid_type;              // 升级文件PID和Type
    //----------------------------------------------------------
    // 升级控制
    uint32_t step;                  // Bit[0]:下传信息;Bit[1]:下传数据;Bit[2]:下传结束；
    uint32_t addr_offset;           // 升级数据偏移量
	uint32_t back_addr_offset;      // 上一次升级数据偏移量
	uint32_t rec_bin_length;        // 接收到数据长度
    uint32_t write_flah_num;        // 写入Flash次数
    uint32_t back_last_flash_adr;   // 最后一次写入Flash的地址

    uint32_t flash_image_sum;       // Flash中临时数据累加和
    uint32_t image_err_flag;        // 升级过程中的错误记录    
    
    uint32_t  timer_out_ms;         // 升级命令间隔，主要是确保不会同一时间段启动两次升级
    uint8_t  timer_tick;            // 对定时器分频
    uint8_t  tick;                  // 下传升级数据时的流水号
}UpgradeInfo_Typedef;

extern uint8_t global_upgrade_stop_herat_flag;
extern volatile bool upgrade_star_flag;
/**
 * @brief 升级数据结构初始化
 * 
 */
void app_updata_init(void);

/**
 * @brief : Timer中断0.5mS调用一次的进程
 * 
 * @param 
 * @return 
 */
void  app_upgrade_timer_irq_callback(void);

/**
 * @brief 将四字节的uint8_t合并成uint32_t
 * 
 * @param p_char    : 要合并的数据指针
 * @return uint32_t : 合并后的结果
 */
uint32_t app_upgrade_pchar_to_uint(uint8_t *p_char);

/**
 * @brief 将二字节的uint8_t合并成uint16_t
 * 
 * @param p_char    : 要合并的数据指针
 * @return uint16_t : 合并后的结果
 */
uint16_t app_upgrade_pchar_to_ushort(uint8_t *p_char);

/**
 * @brief 读取程序版本和PID
 * 
 * @return uint32_t 
 *         Bit[15..0]: 键盘MCU程序版本
 *         Bit[31..24]：键盘程序PID
 */
uint32_t app_upgrade_get_self_ver_pid(void);

/**
 * @brief 读取程序类型
 * 
 * @return uint32_t 
 *         Bit[7..0]: 键盘型号
 *         Bit[11..8]: G-Sensor型号
 *         Bit[14..12]: 键盘NFC型号 
 *         Bit[19..15]：触模板型号
 */
uint32_t app_upgrade_get_self_type(void);

/**
 * @brief 读取设备版本号，一般指触摸板
 * 
 * @return uint32_t 
 *         Bit[23..0]: 设备版本号
 */
uint32_t app_upgrade_get_device_version(void);

/**
 * @brief 下传读取设备程序版本
 * 
 * @param p_buf
 * @param len
 * @return uint8_t 
 *         0x00: 成功
 *         0x03: 升级地址不对
 *         0x04：升级文件长度超过设备Flash容量
 *         0x05：键盘正在升级中，可延时确定键盘程序版本
 */
uint8_t app_upgrade_host_send_read_version(uint8_t *p_buf,uint16_t len);

/**
 * @brief 下传升级信息
 * 
 * @param p_buf
 * @param len
 * @return uint8_t 
 *         0x00: 成功
 *         0x03: 升级地址不对
 *         0x04：升级文件长度超过设备Flash容量
 *         0x05：升级文件PID不对
 *         0x06：键盘正在升级中，可延时确定键盘程序版本
 */
uint8_t app_upgrade_host_send_info(uint8_t *p_buf,uint16_t len);

/**
 * @brief 保存升级文件头信息
 */
void app_upgrade_save_file_info(void);

/**
 * @brief 下传升级数据
 * 
 * @param p_buf
 * @param len
 */
void app_upgrade_host_send_data(uint8_t *p_buf,uint16_t len);

/**
 * @brief 下传升级结束命令
 * 
 * @param p_buf
 * @param len
 * @param p_out 输出信息指针 
 *         Byte[0]: 状态
 *         Byte[1..4]：校验和
 *         Byte[5..8]：错误代码
 */
void app_upgrade_host_send_end(uint8_t *p_buf,uint16_t len);

/**
 * @brief 下传升级结束命令
 * 
 * @param p_sum 临时缓中区中数据累加和
 * @param p_err_code 错误代码
 * @return 是否校验成功
 */
bool app_upgrade_check_temp_image(uint32_t *p_sum,uint32_t *p_err_code);

/**
 * @brief 下传启动升级命令
 * 
 * @param p_buf
 * @param len
 * @param p_out 输出信息指针 
 *         Byte[0]: 状态
 *         Byte[1..4]：校验和
 *         Byte[5..8]：错误代码
 */
void app_upgrade_host_send_start_updata(uint8_t *p_buf,uint16_t len);

/**
 * @brief 下传"开始升级"或"复位"命令
 * 
 * @param p_buf
 * @param len
 * @return uint8_t 
 *         0x00: 成功
 */
uint8_t app_upgrade_start_updata_reset(uint8_t *p_buf,uint16_t len);

/**
 * @brief 升级有关的进程
 * 
 */
void app_upgrade_process(void);

/**
 * @brief upgrade进程,0.1mS调一次
 *
 * @return none
 *
 */
void app_upgrade_reset_timer_0_1ms_callback(void);

#endif

